package bootstrap

import (
	"context"
	"fmt"
	"log"
	"strconv"
	"sync"
	"time"
	"xiehui-service/app/models/bs_models"
	"xiehui-service/app/services/bs_services"
	"xiehui-service/app/services/erp_services"
	"xiehui-service/global"
	"xiehui-service/utils"

	"github.com/robfig/cron/v3"
	"go.uber.org/zap"
)

const SyncDataProduceKey = "sync_produce_time"
const SyncDataPieceKey = "sync_piece_time"

var vZdid string
var vMixerNo string

var mu sync.Mutex
var muProudce sync.Mutex

func InitializeCron() context.CancelFunc {
	ctx, cancel := context.WithCancel(context.Background())

	global.App.Cron = cron.New(cron.WithSeconds())

	vZdid = global.App.Config.App.Zdid
	vMixerNo = global.App.Config.App.MachineNo

	go func() {
		defer global.App.Cron.Stop()

		// 生产记录同步至ERP，生成生产单和发货单 3分钟
		if _, err := global.App.Cron.AddFunc("0 */3 * * * *", func() {
			go SyncProduce()
		}); err != nil {
			global.App.Log.Info("添加生产记录同步任务失败:", zap.Any("失败原因", err))
		}

		// 上报心跳
		if _, err := global.App.Cron.AddFunc("*/30 * * * * *", func() {
			go HeartBeat()
		}); err != nil {
			global.App.Log.Info("添加心跳检测任务失败:", zap.Any("失败原因", err))
		}

		global.App.Cron.Start()
		<-ctx.Done()
	}()
	return cancel
}

// 同步派车信息 20250315的时间戳 45731
func SyncProduce() {
	// key := fmt.Sprintf("%s%s", SyncDataProduceKey, vZdid)
	// lock := global.Lock(key, 60*3)

	muProudce.Lock()
	defer muProudce.Unlock()
	// if lock.Get() {
	log.Println("[04-1]开始派车数据同步==>>")
	global.App.Log.Info("[04-1]开始派车数据同步：")

	paramConfig, err := erp_services.ParamConfigService.GetParamByKey(SyncDataProduceKey, vZdid, vMixerNo)
	if err != nil {
		if err.Error() == "record not found" {
			// 尝试新增配置
			produceStartTime := utils.TimeToAccess(time.Now().Add(-1 * time.Hour))
			_, err = erp_services.ParamConfigService.AddParamByKey(SyncDataProduceKey, fmt.Sprintf("%v", produceStartTime), vZdid, vMixerNo)
			if err == nil {
				global.App.Log.Info("[04]新增参数配置成功：", zap.Any("key", SyncDataProduceKey))
				return
			}
		}

		global.App.Log.Info("[04]【同步派车信息】查询配置信息出错:", zap.Any("原因", err))
		return
	}

	accessTs, err := strconv.ParseFloat(paramConfig.ParamValue, 64)
	if err != nil {
		log.Println("[04-1]配置信息类型转换出错==>>", err)
		// lock.Release()
		return
	}
	// 往前推30分钟
	accessTsMinus30min := accessTs - (0.5 / 24)
	// accessTsMinus30min = 45500.6645479398
	pieceList, err := bs_services.PieceService.PieceFinish(accessTsMinus30min, 100)
	log.Println("pieceList, err==>>", pieceList, err)
	for _, piece := range pieceList {
		log.Println("[04-1]当前数据ID==>>", piece.ID, piece.Produce, "时间==>>", utils.AccessToTime(piece.Stamp))

		produce, err := bs_services.ProduceService.GetOneById(piece.Produce)

		if err != nil {
			log.Println("[04-1]查询三方派车信息失败", err)
			global.App.Log.Info("[04]异常：", zap.Any("查询三方派车信息失败", err))
			// lock.Release()
			return
		}

		generateDelivery(*produce)
		erp_services.ParamConfigService.SetParamByKey(SyncDataProduceKey, utils.StampFloatToStr(piece.Stamp), vZdid, vMixerNo)

	}

	// lock.Block(10)
	// lock.Release()
	// } else {
	// 	log.Println("[04-1]锁已被占用，稍后再试")
	// 	global.App.Log.Info("[04-1]<<==锁已被占用，稍后再试")
	// }
}

// 生成发货单
func generateDelivery(bsProduce bs_models.Produce) {

	// 根据派车单处理发货单
	bsProduceId, err := strconv.Atoi(bsProduce.ID)
	if err != nil {
		global.App.Log.Info("数据类型转换失败", zap.Any("bsProduceId:", bsProduceId))
		return
	}
	unioNo := fmt.Sprintf("FHD_%s_%s_%s", vZdid, vMixerNo, bsProduce.ID)

	// 查询记录是否存在
	erpOrderDelivery, err := erp_services.OrderDeliveryService.GetByUnioNo(unioNo)
	log.Println("erpOrderDelivery==>>", erpOrderDelivery.ID.ID, err)

	erpOrderDelivery.CountVehicle = bsProduce.TotVehs
	erpOrderDelivery.CountQuantity = bsProduce.TotMete
	erpOrderDelivery.ProductionQuantity = bsProduce.ProdMete
	erpOrderDelivery.MortarQuantity = bsProduce.MorMete
	// 车辆处理
	vechicleId, err := strconv.Atoi(bsProduce.Vehicle)
	if err != nil {
		global.App.Log.Info("[生成发货单]数据类型转换失败:", zap.Any("失败原因", err))
	}
	vehicle, err := bs_services.VehicleService.GetByID(uint(vechicleId))
	if err != nil {
		global.App.Log.Info("[生成发货单]查询车辆数据失败:", zap.Any("失败原因", err))
	}
	if vehicle != nil {
		erpOrderDelivery.VehicleNo = vehicle.Code
	}

	// 记录已存在
	if erpOrderDelivery.ID.ID > 0 {
		t, err := time.ParseInLocation(time.DateTime, utils.TimeFormat(bsProduce.LeftTim), time.Local)
		if err != nil {
			log.Println("离开时间转换出错")
		}
		erpOrderDelivery.LeaveTime = &t

		err = erp_services.OrderDeliveryService.Update(erpOrderDelivery)
		if err != nil {
			global.App.Log.Info("数据更新失败", zap.Any("erpOrderDelivery:", erpOrderDelivery))
			log.Println("更新发货单信息失败", err)
		}
		log.Println("更新ERP发货单信息成功", erpOrderDelivery.ID.ID)
		global.App.Log.Info("更新ERP发货单成功:", zap.Any("ERP发货单ID", erpOrderDelivery.ID.ID))
		return
	}

	// 生成发货单
	erpOrderDelivery.LineId = vMixerNo
	erpOrderDelivery.UnionNo = unioNo
	erpOrderDelivery.DeliveryNo = unioNo
	erpOrderDelivery.CustomerName = bsProduce.Customer
	erpOrderDelivery.ProjectName = bsProduce.ProjName
	erpOrderDelivery.BuildPosition = bsProduce.ConsPos
	erpOrderDelivery.BuildMethod = bsProduce.Pour
	erpOrderDelivery.VehicleContacts = bsProduce.Driver
	erpOrderDelivery.ProjectSubName = bsProduce.ProjName
	erpOrderDelivery.MixerNo = global.App.Config.App.MachineNo

	erpOrderDelivery.HaulDistance = strconv.FormatFloat(bsProduce.Distance, 'f', 2, 64)
	erpOrderDelivery.ShippingAddress = bsProduce.ProjAdr
	erpOrderDelivery.PlanQuantity = bsProduce.ProdMete
	erpOrderDelivery.ConcreteCategory = bsProduce.BetLev
	erpOrderDelivery.DeliveryQuantity = bsProduce.ProdMete
	erpOrderDelivery.VehicleNo = bsProduce.Vehicle
	erpOrderDelivery.VehicleContacts = bsProduce.Driver

	erpOrderDelivery.TaskId = 0
	erpOrderDelivery.TaskNo = bsProduce.Code
	erpOrderDelivery.Strength = bsProduce.BetLev

	erpOrderDelivery.DeliveryStatus = 2
	erpOrderDelivery.WorkMixtureNo = bsProduce.Recipe

	strTime := utils.TimeFormat(bsProduce.DatTim)
	if strTime != "" {
		ct, err := time.ParseInLocation(time.DateTime, strTime, time.Local)
		if err != nil {
			log.Println("发货单创建时间转换失败")
			global.App.Log.Info("发货单创建时间转换失败", zap.Any("DatTim:", err))
			return
		}
		erpOrderDelivery.CreatedAt = ct
	}

	deliveryTime := utils.TimeFormat(bsProduce.ProdTimE)
	dt, err := time.ParseInLocation(time.DateTime, deliveryTime, time.Local)
	if err != nil {
		log.Println("发货时间转换失败")
		global.App.Log.Info("发货时间转换失败", zap.Any("ProdTimE:", err))
		return
	}
	erpOrderDelivery.DeliveryTime = dt

	id, err := erp_services.OrderDeliveryService.Create(erpOrderDelivery)
	if err != nil {
		global.App.Log.Info("新增ERP发货单失败：", zap.Any("失败原因", err))
		return
	}

	log.Println("新增ERP发货单：", id)
	global.App.Log.Info("新增ERP发货单成功:", zap.Any("ERP发货单ID", id))
}

// 心跳上报
func HeartBeat() {
	mu.Lock()
	defer mu.Unlock()
	log.Println("[05]开始心跳上报==>>")
	global.App.Log.Info("[05]开始心跳上报：")

	_, err := erp_services.LineService.SetById(vZdid, vMixerNo)
	if err != nil {
		log.Println("[05]心跳上报失败：", err)
		global.App.Log.Info("[05]心跳上报失败：", zap.Any("失败原因", err))
		return
	}
	log.Println("[05]心跳上报成功：", vZdid)
	global.App.Log.Info("[05]心跳上报成功：", zap.Any("站点id", vZdid))
}
